#ifndef CALCULATOR_H
#define CALCULATOR_H

/**
 * @file   calculator.h
 * @author ywl <ywl@ywl-VirtualBox>
 * @date   Sun Nov 21 21:01:56 2021
 * 
 * @brief  设计一个四则混合运算器
 * 
 * 
 */
#include <stack>
#include <vector>
#include <string>
#include <cmath>
#include <iostream>
#include <cstdlib>
using namespace std;


class calculator
{
public:
    calculator( );
    void getFormat( );		//表达式自定义标准格式化
    int getPrior( char c );	//获取算术符号优先级
    void getPostfix( );		//后缀表达式转换
    void calResult( );		//计算后缀表达式
    void calculate( );		//计算方法
    double getResult( );	//获取结果

    string operatorSym;		//运算符号
    string infix;		//表达式缓存

private:
    vector<string> postfix;	//后缀表达式向量
    stack<char> symStack;	//符号栈
    stack<double> figStack;	//数字栈
    string stdInfix;
    double result;
    void Error( );		//报错并退出
 };

/**
 * 算术符号优先级等级
 * 
 */
enum PRIO_LV
{
    PRIO_LV0 = 0,
    PRIO_LV1 = 1,
    PRIO_LV2 = 2,
};

/**
 * 构造函数，初始化成员变量
 * 
 */
calculator::calculator( )
{
    operatorSym = "支持运算符： +， -， *, /, ()";
    result = 0.0;   
}

/** 
 * 自定义表达式标准格式化
 * 
 */
void calculator::getFormat( )
{
    stdInfix = infix;
    
    /// 报错并退出
    if( stdInfix[0] == '+' || stdInfix[0] == '*' || stdInfix[0] == '/' )
	Error( );
    /// 第一位为小数点或者为‘-’
    if( stdInfix[0] == '.' || stdInfix[0] == '-' )
	stdInfix.insert( 0, 1, '0' );
    
}

/** 
 * 获取算术符号优先级
 * 
 * @param c 
 * 
 * @return 
 */
int calculator::getPrior( char c )
{
    if( c == '+' || c == '-' )
    {
	return PRIO_LV1;
    }

    if( c == '*' || c == '/' )
    {
	return PRIO_LV2;
    }

    else
    {
	return PRIO_LV0;
    }
}

/** 
 * 后缀表达式转换
 * 
 */
void calculator::getPostfix( )
{
    string tmp;
    
	for( size_t i = 0; i < stdInfix.size( ); i++ )		//string.size( )返回size_type类型，避免下标运算时类型溢出
	{
	    tmp = "";
	    switch( stdInfix[i] ){
	    case '+':
	    case '-':
	    case '*':
	    case '/':
		if( symStack.empty( ) || symStack.top( ) == '(' || symStack.top( ) == '[' || symStack.top( ) == '{' )
		    symStack.push( stdInfix[i] );
		else
		{
		    while( !symStack.empty( ) && ( getPrior( symStack.top( ) ) >= getPrior( stdInfix[i] ) ) )
		    {
			tmp += symStack.top( );
			postfix.push_back( tmp );
			symStack.pop( );
			tmp = "";
		    }
		symStack.push( stdInfix[i] );
		}
		break;
		
	    case '(':
		if( !symStack.empty( ) && symStack.top( ) == '(' )		//栈顶为（，报错并退出
		{
		    Error( );
		}
		symStack.push( stdInfix[i] );
		break;

	    case ')':
		while( !symStack.empty( ) && symStack.top( ) != '(' )
		{
		   tmp += symStack.top( );
		   postfix.push_back( tmp );
		   symStack.pop( );
		   tmp = ""; 
		}
		/// 如果没有相应的‘（’，则报错退出
		if( symStack.empty( ) )
		{
		    Error( );
		}
		if( symStack.top( ) == '(' )
		{
		    symStack.pop( );
		}
		break;
		
	    default:
		if( stdInfix[i] >= '0' && stdInfix[i] <= '9' )
		{
		    tmp += stdInfix[i];
		    int count = 0;	//统计一个数据中小数点的个数
		    /// 防止数组越界以及小数处理
		    while( i+1 < stdInfix.size() && ( ( stdInfix[i+1] >= '0' && stdInfix[i+1] <= '9' ) || stdInfix[i+1] == '.' ) )
		    {
			if( stdInfix[i+1] == '.' )
			{   if( ++count > 1 )
			    /// 多于1则报错退出
			    Error( );
			}
			tmp += stdInfix[i+1];	//是连续的数字则追加
			i++;
		    }
		    /// 将x.转化为x.0
		    if( tmp[tmp.size( )-1] == '.' )
			tmp += '0';
		    
		    postfix.push_back( tmp );
		}
		break;
	    }//end switch
		
	}//end for

	/// 将栈中剩余的符号加入后缀表达式
	
	while( !symStack.empty( ) )
	{
	    tmp = "";
	    tmp += symStack.top( );
	    postfix.push_back( tmp );
	    symStack.pop( );
	}
}

/** 
 * 计算后缀表达式
 * 
 */
void calculator::calResult( )
{
    string tmp;
    double number = 0;
    double op1 = 0, op2 = 0;

    for( int i = 0; i < postfix.size( ); i++ )
    {
	tmp = postfix[i];
    // 后缀表达式中的数值元素可能是多位或者小数，比如"234"、"2.34"等 
	if( tmp[0] >= '0' && tmp[0] <= '9' )
	{
	    number = atof( tmp.c_str( ) );
	    figStack.push( number ); 
	}
    else if( postfix[i] == "+" )
    {
	    op2 = figStack.top( );
	    figStack.pop( );
	    if( figStack.empty( ) )
	    {
		figStack.push( 0 );	//第二个加数没有则加0
	    }
	    op1 = figStack.top( );
	    figStack.pop( );

	    figStack.push( op1+op2 );
    }
    else if( postfix[i] == "-" )
    {
	    op2 = figStack.top( );
	    figStack.pop( );
	    if( figStack.empty( ) )
	    {
		figStack.push( 0 );	//第二个减数没有则减0
		op1 = figStack.top( );
		figStack.pop( );

		figStack.push( op2-op1 );
	    }
	    else{
	    op1 = figStack.top( );
	    figStack.pop( );

	    figStack.push( op1-op2 );
	    }
    }
    else if( postfix[i] == "*" )
    {
	    op2 = figStack.top( );
	    figStack.pop( );
	    if( figStack.empty( ) )
	    {
		figStack.push( 1 );	//第二个乘数没有则乘1
	    }
	    op1 = figStack.top( );
	    figStack.pop( );

	    figStack.push( op1*op2 );
    }
    else if( postfix[i] == "/" )
    {
	    op2 = figStack.top( );
	    figStack.pop( );
	    if( figStack.empty( ) )
	    {
		Error( );	//第二个除数没有则报错退出
	    }
	    if( op2== 0 )
		Error( );	//除数为0则报错退出
	    op1 = figStack.top( );
	    figStack.pop( );

	    figStack.push( op1/op2 );
    }
	
    }//end for

    if( !figStack.empty( ) )
    {
	result = figStack.top( );
    }
	
}

/** 
 * 计算方法
 * 
 */
void calculator::calculate( )
{
    getFormat( );	//表达式自定义标准格式化
    getPostfix( );	//后缀表达式转换
    calResult( );	//计算后缀表达式
}

/** 
 * 获取结果
 * 
 * 
 * @return 
 */
double calculator::getResult( )
{
    return result;
}
 

/** 
 * 报错并退出
 * 
 */
void calculator::Error( )
{
    cerr << "Error" << endl;
    abort( );
}

#else
#endif
